//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<timer_center.cpp>
///	@path	~/src/engine/xcore/
///	@date	2007/12/31
///	@desc	Timer center.

#include "config/config.h"

#include "lib/utilities/observer.h"
#include "lib/system/thread_debug.h"

#include "engine/xcore/timer_center.h"

namespace xeres {

	// TimerCenter
	TimerCenter::TimerCenter( void )
		: m_ticking( false )
	{
	}

	// ~TimerCenter
	TimerCenter::~TimerCenter( void )
	{

	}

	// Initialize
	void TimerCenter::Initialize( void )
	{
	}

	// Finalize
	void TimerCenter::Finalize( void )
	{
		m_timers.clear();
		m_nestingTimers.clear();
	}

	// InsertTimer
	void TimerCenter::InsertTimer( float run_after_sec , function<void(float)> call )
	{
		TRACK_FUNCTION_SCOPE();
		RUNNING_ON_THREAD( _S("main|tick|!_render") );

		// < 30fps , run them immediately
		if( run_after_sec <= ( 1.f / 30.f ) )
		{
			m_immediate.push_back( call );
		}
		else
		{
			float stamp = m_stamp + run_after_sec;
			if( m_ticking )
			{
				m_nestingTimers.insert( _CallBack( stamp , call ) );
			}
			else
			{
				m_timers.insert( _CallBack( stamp , call ) );
			}
		}
	}

	namespace
	{
		// a boolean value guard
		class _TagGuard
		{
		public:
			//@ ctor
			_TagGuard( bool& tag , bool value )
				: m_tag( tag )
			{
				// initialize the tag with value
				m_tag = value;
			}
			//@ dtor
			~_TagGuard( void )
			{
				// revert it while scope ends
				m_tag = !m_tag;
			}
		private:
		//@ dtor
			bool& m_tag;
		};
	}

	// Tick
	void TimerCenter::Tick( const Frame& frame )
	{
		TRACK_FUNCTION_SCOPE();
		RUNNING_ON_THREAD( _S("tick|!_render") );

		COUNTER_GUARD( _S("timer") );

		if( !m_immediate.empty() )
		{
			for( size_t i = 0 , total = m_immediate.size() ; i < total ; ++i )
			{
				m_immediate[i]( 0 );
			}
			m_immediate.clear();
		}

		if( !m_timers.empty() )
		{
			_TagGuard tagGuard( m_ticking , true );
			m_stamp = frame.gtime();

			_TimerQueue::iterator begin = m_timers.begin();
			if( begin->first <= m_stamp )
			{
				_TimerQueue::iterator end = m_timers.upper_bound( m_stamp );
				_TimerQueue::iterator it = begin;

				while( it != end )
				{
					it->second( m_stamp - it->first );
					++it;
				}
				m_timers.erase( begin , end );
			}

			// update newly inserted timers while ticking.
			if( m_nestingTimers.size() > 0 )
			{
				m_timers.insert( m_nestingTimers.begin() , m_nestingTimers.end() );
				m_nestingTimers.clear();
			}
		}
	}

} // namespace xeres
